package com.ruoyi.common.core.dao;

import java.io.Serializable;
import java.lang.InstantiationException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import com.ruoyi.common.core.dao.dialect.DBFuctionFactroy;
import com.ruoyi.common.core.dao.dialect.FuncAdapter;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.page.Page;
import com.ruoyi.common.utils.spring.SpringUtils;
import org.hibernate.*;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.query.NativeQuery;
import org.hibernate.query.Query;
import org.hibernate.transform.Transformers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate5.HibernateCallback;
import org.springframework.orm.hibernate5.HibernateTemplate;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.persistence.EntityManagerFactory;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * Dao基础类
 * @author liuyj
 * 实现Dao的基础操作封装，包括增加、删除、修改、获取、查询等方法
 */
@Transactional
public class BaseDao <T, ID extends Serializable>{
    @Autowired
    private EntityManagerFactory entityManagerFactory;
    protected String defaultOrder = "";
    protected Class modelClass;
    protected FuncAdapter sqlUtil;

    public SessionFactory getSessionFactory() {
        return entityManagerFactory.unwrap(SessionFactory.class);
    }
    private HibernateTemplate getHibernateTemplate(){
        return new HibernateTemplate(getSessionFactory());
    }
    @Transactional
    public Session openSession () {
        return entityManagerFactory.unwrap(SessionFactory.class).openSession();
    }
    @Transactional
    public Session getCurrentSession() {
        return entityManagerFactory.unwrap(SessionFactory.class).getCurrentSession();
        //return getSessionFactory().getCurrentSession();
    }

    protected Class entityClazz;

    public BaseDao() {
        // 获取当前Dao所指定的Entity的Class
        Class clazz = this.getClass();
        Type genericSuperclass = clazz.getGenericSuperclass();
        if (genericSuperclass instanceof ParameterizedType) {
            Type[] actualTypeArguments = ((ParameterizedType) genericSuperclass)
                    .getActualTypeArguments();
            if (actualTypeArguments != null && actualTypeArguments.length > 0) {
                entityClazz = (Class<?>) actualTypeArguments[0];
            }
        }
        this.sqlUtil = DBFuctionFactroy.getFuncAdapter();
    }

    public Class<T> getEntityClass() {
        return entityClazz;
    }
    /**
     * 获取model对象
     * @param id id
     * @return model对象
     * 
     */
    public final Object getObject(long id){
        Serializable idTemp = new Long(id);
        return getObject(idTemp);
    }

    /**
     * 获取model对象
     * @param id id
     * @return model对象
     * 
     */
    public final Object getObject(int id) {
        Serializable idTemp = new Long(id);
        return getObject(idTemp);
    }

    /**
     * 获取model对象
     * @param id id
     * @return model对象
     * 
     */
    public final Object getObject(String id) {
        Serializable idTemp = new String(id);
        return getObject(idTemp);
    }

    /**
     * 获取model对象
     * @param id id
     * @return model对象
     * 
     */
    public final Object getObject(Serializable id) {        
        return getHibernateTemplate().get(getEntityClass(), id);
    }

    /**
     * 添加model对象
     * @param modelObject model对象
     * 
     */
    public final void addObject(Object modelObject) {
        //getHibernateTemplate().save(modelObject);
        getCurrentSession().save(modelObject);
    }

    /**
     * 保存model对象
     * @param modelObject model对象
     * 
     */
    public final void saveObject(Object modelObject) {
        getCurrentSession().saveOrUpdate(modelObject);
        //getHibernateTemplate().saveOrUpdate(modelObject);
    }

    /**
     * 更新model对象
     * @param modelObject model对象
     * 
     */
    public final void updateObject(Object modelObject) {
        getCurrentSession().merge(modelObject);
        //getHibernateTemplate().update(modelObject);
    }

    /**
     * 删除model对象
     * @param id id
     * 
     */
    public final void deleteObject(long id) {
        Serializable idTemp = new Long(id);
        deleteObject(idTemp);
    }

    /**
     * 删除model对象
     * @param id id
     * 
     */
    public final void deleteObject(int id) {
        Serializable idTemp = new Long(id);
        deleteObject(idTemp);
    }

    /**
     * 删除model对象
     * @param id id
     * 
     */
    public final void deleteObject(String id) {
        Serializable idTemp = new String(id);
        deleteObject(idTemp);
    }

    /**
     * 删除model对象
     * @param id id
     * 
     */
    public final void deleteObject(Serializable id) {
        Object object = this.getObject(id);
        //getHibernateTemplate().delete(object);
        getCurrentSession().delete(object);
    }

    /**
     * 获取model集合
     * @return model集合
     * 
     */
    @Transactional
    public List getObjects() {
        String queryString = "";
        System.out.println("name="+getEntityClass().getSimpleName());
        queryString = "from " + getEntityClass().getSimpleName() + getDefaultOrder();
        return find(queryString);
    }

    /**
     * 保存model集合
     * 
     */
    public final void saveList(final List modelList) {
        getHibernateTemplate().executeWithNativeSession(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException {
                int count = 0;
                for (Object obj : modelList) {
                    session.saveOrUpdate(obj);
                    count++;
                    if (count == 100) {
                        count = 0;
                        session.flush();
                    }
                }
                session.flush();
                return null;
            }
        });

    }

    /**
     * 查找hql语句
     * @param queryString hql语句
     * @return 查询结果
     */
    @Transactional
    protected List find(String queryString) {

        return getCurrentSession().createQuery(queryString).list();
        //return getHibernateTemplate().getSessionFactory().getCurrentSession().createQuery(queryString).list();

    }

    /**
     * 查找hql语句
     * @param queryString hql语句
     * @param value 查询值
     * @return 查询结果
     */
    protected final List find(String queryString, String value) {
        return getCurrentSession().createQuery(queryString).setParameter(1,value).list();
        //return getHibernateTemplate().find(queryString, value);

    }

    /**
     * 查找hql语句
     * @param queryString hql语句
     * @param values 查询值组
     * @return 查询结果
     */
    protected final List find(String queryString, Object[] values) {
        Query query=getCurrentSession().createQuery(queryString);
        for(int i=0;i<values.length;i++){
            query.setParameter(i+1,values[i]);
        }
        return  query.list();
        //return getHibernateTemplate().find(queryString, values);

    }

    /**
     * 分页查询所有数据
     * @param currPage 当前页
     * @param pageSize 每页显示行数
     * @return 查询结果
     */
    public final Page findPage(int currPage, int pageSize) {
        String queryString = "";

        queryString = "from " + entityClazz.getSimpleName() + getDefaultOrder();
        Session session = getCurrentSession();
        int totalCount = countDataTotal(queryString, session);

        int startRow = (currPage - 1) * pageSize;
        if (startRow < 0) startRow = 0;
        Query query = session.createQuery(queryString).setFirstResult(startRow).setMaxResults(pageSize);

        List modelList = query.list();
        return new Page(modelList, totalCount);

    }

    /**
     * 查询hql语句
     * @param queryString hql语句
     * @param currPage 当前页
     * @param pageSize 每页显示行数
     * @return 查询结果
     */
    protected final Page findPage(String queryString, int currPage, int pageSize) {
        Session session = getCurrentSession();
        int totalCount = countDataTotal(queryString, session);
        int startRow = (currPage - 1) * pageSize;
        if (startRow < 0) startRow = 0;
        Query query = session.createQuery(queryString).setFirstResult(startRow).setMaxResults(pageSize);
        List modelList = query.list();
        return new Page(modelList, totalCount);
    }

    /**
     * 统计记录总数
     * @param queryString 查询hql语句
     * @param session hibernate的Session对象
     * @return 记录总数 2012-3-12 gavin lee 修改方法为保护类型的，允许子类能够覆盖这个方法，处理比较特殊的sql脚本查询
     */
    protected int countDataTotal(String queryString, Session session) {

            int totalCount = 0;
            String lowerHql = queryString.trim().toLowerCase();
            int fromPos = 0;
            int orderPos = lowerHql.length();
            if (!lowerHql.startsWith("from ")) fromPos = lowerHql.indexOf(" from ") + 1;
            orderPos = lowerHql.indexOf(" order by ") + 1;

            String countHql;
            if (orderPos != 0)
                countHql = "select count(*) " + queryString.substring(fromPos, orderPos);
            else
                countHql = "select count(*) " + queryString.substring(fromPos);

            int distinctPos = lowerHql.indexOf(" distinct ");

            if (distinctPos >= 0 && distinctPos < fromPos) {
                totalCount = session.createQuery(queryString).list().size();
            }
            else {
                Object value = session.createQuery(countHql).uniqueResult();
                if (value == null) {
                    totalCount = 0;
                }
                else {
                    totalCount = ((Long) value).intValue();
                }
            }
            return totalCount;

    }

    /**
     * 查询sql语句
     * @param sql sql语句
     * @return 查询结果
     */
    protected final List findBySQL(final String sql) {
        Query query=getCurrentSession().createSQLQuery(sql).addEntity(getEntityClass());
        return  query.list();
    }

    /**
     * 查询sql语句
     * @param sql sql语句
     * @param paramArray 参数列表
     * @return 查询结果
     */
    protected final List findBySQL(final String sql, final Object[] paramArray) {
        Query sqlQuery=getCurrentSession().createNativeQuery(sql,entityClazz);
        for (int i = 0; i < paramArray.length; i++) {
            sqlQuery.setParameter(i, paramArray[i]);
        }
        return sqlQuery.list();
    }

    /**
     * 查询sql语句
     * @param sqlBuilder sql构造对象，包含了sql和参数列表
     * @return 查询结果
     */
    protected final List findBySQL(ParamSqlBuilder sqlBuilder) {
        return findBySql(sqlBuilder, true);
    }

    /**
     * 内部查询sql，使用sql构造器进行查询，注意判断参数类型来设置参数
     * @param sqlBuilder sql构造器
     * @param isBuildEntity 是否构造为实体
     * @return
     */
    private List findBySql(ParamSqlBuilder sqlBuilder, final boolean isBuildEntity) {
        final String sql = sqlBuilder.getSql();
        final Map<String, Object> paramMap = sqlBuilder.getParamMap();
        final String paramType = sqlBuilder.getParamType();
        Object[] keys = paramMap.keySet().toArray();
        Arrays.sort(keys);
        StringBuilder sb = new StringBuilder();
        for (Object key : keys) {
            sb.append("param").append(key).append("=").append(paramMap.get(key)).append(",");
        }
        //log.debug("sql= [{}],paramList= [{}]", sql, sb.toString());
        Query sqlQuery;
        if (isBuildEntity) {
            sqlQuery=getCurrentSession().createNativeQuery(sql,entityClazz);
        }else{
            sqlQuery=getCurrentSession().createNativeQuery(sql);
        }
        for (String key : paramMap.keySet()) {
            if (ParamSqlBuilder.INDEXPARAM.equals(paramType)) {
                sqlQuery.setParameter(Integer.parseInt(key), paramMap.get(key));
            }
            else {
                sqlQuery.setParameter(key, paramMap.get(key));
            }
        }
        return sqlQuery.list();

    }

    /**
     * 查询灵活的sql语句
     * @param sqlBuilder sql构造器，包含了sql和参数
     * @return 查询结果
     */
    protected final List findByFreeSQL(ParamSqlBuilder sqlBuilder) {
        return findBySql(sqlBuilder, false);
    }

    /**
     * 查询灵活的sql语句
     * @param sql 灵活的sql语句（不受model影响）
     * @param paramArray 参数列表
     * @return 查询结果
     */
    protected final List findByFreeSQL(final String sql, final Object[] paramArray) {
        Query query=getCurrentSession().createNativeQuery(sql);
        for (int i = 0; i < paramArray.length; i++) {
            query.setParameter(i, paramArray[i]);
        }
        return  query.list();
    }

    /**
     * 查询灵活的sql语句(返回指定的实体类)
     * @param sql 灵活的sql语句
     * @param paramArray 参数列表
     * @param outModelClass 指定外部实体类
     * @return 查询结果
     */
    protected final List findByFreeSQL(final String sql, final Object[] paramArray, final Class outModelClass) {
        Query sqlQuery=getCurrentSession().createNativeQuery(sql,outModelClass);
        for (int i = 0; i < paramArray.length; i++) {
            sqlQuery.setParameter(i, paramArray[i]);
        }
        return  sqlQuery.list();
    }

    /**
     * 查询灵活的sql语句
     * @param sql 灵活的sql语句（不受model影响）
     * @return 查询结果
     */
    protected final List findByFreeSQL(final String sql) {
        Query sqlQuery=getCurrentSession().createSQLQuery(sql);
        return sqlQuery.list();
    }

    /**
     * 查询灵活的sql语句(返回指定的实体类)
     * @param sql 灵活的sql语句
     * @param outModelClass 指定外部实体类
     * @return 查询结果
     */
    protected final List findByFreeSQL(final String sql, final Class outModelClass) {
        Query sqlQuery=getCurrentSession().createSQLQuery(sql).addEntity(outModelClass);
        //NativeQuery sqlQuery=getCurrentSession().createNativeQuery(sql, outModelClass);
        return sqlQuery.getResultList();
    }

    /**
     * 查询sql语句
     * @param sql sql语句
     * @param currPage 当前页
     * @param pageSize 每页显示行数
     * @return 查询结果
     */
    protected final Page findPageBySQL(String sql, int currPage, int pageSize) {
        Session session = getCurrentSession();
        int totalCount = countDataTotalBySQL(sql, session);

        int startRow = (currPage - 1) * pageSize;
        if (startRow < 0) startRow = 0;
        Query query = session.createSQLQuery(sql).addEntity(getEntityClass()).setFirstResult(startRow).setMaxResults(pageSize);

        List modelList = query.list();
        return new Page(modelList, totalCount);

    }

    /**
     * 查询灵活的sql语句
     * @param sql 灵活的sql语句（不受model影响）
     * @param currPage 当前页
     * @param pageSize 每页显示行数
     * @return 查询结果
     */
    protected final Page findPageByFreeSQL(String sql, int currPage, int pageSize) {
        Session session = getCurrentSession();
        int totalCount = countDataTotalBySQL(sql, session);

        int startRow = (currPage - 1) * pageSize;
        if (startRow < 0) startRow = 0;
        Query query = session.createSQLQuery(sql).setFirstResult(startRow).setMaxResults(pageSize);

        List modelList = query.list();
        return new Page(modelList, totalCount);
    }

    /**
     * 查询灵活的sql语句(返回指定的实体类)
     * @param sql 灵活的sql语句（不受model影响）
     * @param currPage 当前页
     * @param pageSize 每页显示行数
     * @param outModelClass 指定外部实体类
     * @return 查询结果
     */
    protected final Page findPageByFreeSQL(String sql, int currPage, int pageSize, final Class outModelClass) {

        Session session = getCurrentSession();
        int totalCount = countDataTotalBySQL(sql, session);

        int startRow = (currPage - 1) * pageSize;
        if (startRow < 0) startRow = 0;
        Query query = session.createSQLQuery(sql).addEntity(outModelClass).setFirstResult(startRow).setMaxResults(pageSize);

        List modelList = query.list();
        return new Page(modelList, totalCount);
    }

    /**
     * 执行SQL语句返回受影响的记录数
     * @String sql sql语句
     * @return int 受影响的记录数
     */
    protected final int executeSql(final String sql) {

            Integer obj = (Integer) getHibernateTemplate().execute(new HibernateCallback() {
                public Object doInHibernate(Session session) throws HibernateException {
                    // 在SQL语句中加入修改时间和传输状态
                    int updateCount = session.createSQLQuery(sql).executeUpdate();
                    return Integer.valueOf(updateCount);
                }
            });
            return obj == null ? 0 : obj.intValue();

    }

    /**
     * 执行SQL语句返回受影响的记录数
     * @String hql hql语句
     * @return int 受影响的记录数
     */
    protected final int executeHql(final String hql) {

            Integer obj = (Integer) getHibernateTemplate().execute(new HibernateCallback() {
                public Object doInHibernate(Session session) throws HibernateException {
                    int updateCount = session.createQuery(hql).executeUpdate();
                    return new Integer(updateCount);
                }
            });
            return obj == null ? 0 : obj.intValue();

    }

    /**
     * 统计记录总数
     * @param sql 查询sql语句
     * @param session hibernate的Session对象
     * @return 记录总数 2012-3-12 gavin lee 修改方法为保护类型的，允许子类能够覆盖这个方法，处理比较特殊的sql脚本查询
     */
    protected int countDataTotalBySQL(String sql, Session session) {

            int totalCount = 0;
            String lowerHql = sql.trim().toLowerCase();
            int fromPos = 0;
            int orderPos = lowerHql.length();
            fromPos = lowerHql.indexOf(" from ") + 1;
            orderPos = lowerHql.indexOf(" order by ") + 1;

            String countSql;
            if (orderPos != 0)
                countSql = "select count(*) as num " + sql.substring(fromPos, orderPos);
            else
                countSql = "select count(*) as num " + sql.substring(fromPos);

            int distinctPos = lowerHql.indexOf(" distinct ");

            if (distinctPos >= 0 && distinctPos < fromPos) {
                totalCount = session.createSQLQuery(sql).list().size();
            }
            else {
                Object value = session.createSQLQuery(countSql).uniqueResult();
                if (value == null) {
                    totalCount = 0;
                }
                else {
                    totalCount = ((Long) value).intValue();
                }
            }
            return totalCount;

    }

    /**
     * 获取默认的排序
     * @return
     */
    private String getDefaultOrder() {
        if (defaultOrder==null) return "";
        if (defaultOrder.trim().equals(""))
            return "";
        else {
            String lowerHql = defaultOrder.trim().toLowerCase();
            if (lowerHql.indexOf("order by") == 0)
                return " " + defaultOrder;
            else
                return " order by " + defaultOrder;
        }
    }

    /**
     * 根据用户对象，获取数据过滤的HQL语句
     * @param user 用户对象
     * @return
     */
    /**
    public String getFilterHql(User user) {
        String modelName = modelClass.getSimpleName();
        return getFilterHql(user, null, modelName);
    }*/

    /**
     * 根据用户对象，获取数据过滤的HQL语句
     * @param user 用户对象
     * @param aliasName 别名
     * @return
     */
    /**
    public String getFilterHql(User user, String aliasName) {
        String modelName = modelClass.getSimpleName();
        return getFilterHql(user, aliasName, modelName);
    }*/

    /**
     * 根据用户对象，获取数据过滤的HQL语句
     * @param user 用户对象
     * @param aliasName 别名
     * @param modelName 实体类名
     * @return
     */
    /**
    public String getFilterHql(User user, String aliasName, String modelName) {
        List<DataFilterObject> dataFilterList = user.getDataFilterList();
        // 用户未设置过滤条件
        if (ValidateUtil.isEmpty(dataFilterList)) {
            return "(1=1)";
        }
        Object groupIdObject = DataControlManger.modelNameMap.get(modelName);
        // 表未设置组合
        if (groupIdObject == null) {
            return "(1=1)";
        }
        long groupId = Long.parseLong(groupIdObject.toString());
        for (DataFilterObject dataFilterObject : dataFilterList) {
            // 组合ID匹配
            if (dataFilterObject.getGroupdId() == groupId) {
                String groupFilterId = String.valueOf(dataFilterObject.getGroupFilterId());
                String filterHql = DataControlManger.hqlFilterMap.get(groupFilterId).toString();
                if (ValidateUtil.isEmpty(aliasName)) {
                    filterHql = filterHql.replace("#.", "");
                }
                else {
                    filterHql = filterHql.replace("#.", aliasName + ".");
                }
                return "(" + filterHql + ")";
            }
        }
        return "(1=1)";
    }*/

    /**
     * 根据用户对象，获取数据过滤的SQL语句
     * @param user 用户对象
     * @return
     */
    /**
    public String getFilterSql(User user) {
        String modelName = modelClass.getSimpleName();
        return getFilterSql(user, null, modelName);
    }
    */
    /**
     * 根据用户对象，获取数据过滤的HQL语句
     * @param user 用户对象
     * @param aliasName 别名
     * @return
     */
    /**
    public String getFilterSql(User user, String aliasName) {
        String modelName = modelClass.getSimpleName();
        return getFilterSql(user, aliasName, modelName);
    }*/

    /**
     * 根据用户对象，获取数据过滤的SQL语句
     * @param user 用户对象
     * @param aliasName 别名
     * @param modelName 实体类名
     * @return
     */
    /**
    public String getFilterSql(User user, String aliasName, String modelName) {
        List<DataFilterObject> dataFilterList = user.getDataFilterList();
        // 用户未设置过滤条件
        if (ValidateUtil.isEmpty(dataFilterList)) {
            return "(1=1)";
        }
        Object groupIdObject = DataControlManger.modelNameMap.get(modelName);
        // 表未设置组合
        if (groupIdObject == null) {
            return "(1=1)";
        }
        long groupId = Long.parseLong(groupIdObject.toString());
        for (DataFilterObject dataFilterObject : dataFilterList) {
            // 组合ID匹配
            if (dataFilterObject.getGroupdId() == groupId) {
                String groupFilterId = String.valueOf(dataFilterObject.getGroupFilterId());
                String filterHql = DataControlManger.sqlFilterMap.get(groupFilterId).toString();
                if (ValidateUtil.isEmpty(aliasName)) {
                    filterHql = filterHql.replace("#.", "");
                }
                else {
                    filterHql = filterHql.replace("#.", aliasName + ".");
                }
                return "(" + filterHql + ")";
            }
        }
        return "(1=1)";
    }
    */

    /**
     * 取得对象的主键名.
     */
    public String getIdName() {
        ClassMetadata meta = getSessionFactory().getClassMetadata(entityClazz);
        return meta.getIdentifierPropertyName();
    }

}
